﻿using System;
using System.Linq;
using System.ServiceModel;
using System.Xml;

using TraceView.Shared;

namespace TraceView.Service
{
    public sealed class TraceServiceHost : IDisposable
    {
        private ServiceHost _serviceHost;
        private bool _opened;
        private readonly IDisplayTrace _display;

        public TraceServiceHost(IDisplayTrace display)
        {
            _display = display;
            Open();
        }

        public void Close()
        {
            ((IDisposable)this).Dispose();
        }

        #region IDisposable Members
        void IDisposable.Dispose()
        {
            try
            {
                _serviceHost.Opened -= ServiceHostOpened;
                _serviceHost.Faulted -= ServiceHostFaulted;
                _serviceHost.Close();
            }
            catch
            {
                try
                {
                    _serviceHost.Abort();
                }
                catch (Exception) {}
            }
        }
        #endregion

        private void Open()
        {
            var service = new TraceService(_display);

            _serviceHost = new ServiceHost(service);
            _serviceHost.Description.Endpoints.Clear();

            var binding = new NetTcpBinding(SecurityMode.None, false) {
                ReaderQuotas = XmlDictionaryReaderQuotas.Max,
                MaxReceivedMessageSize = int.MaxValue,
            };
            _serviceHost.AddServiceEndpoint(typeof(ITraceService), binding, "net.tcp://localhost:9001/TraceView");

            _serviceHost.Opened += ServiceHostOpened;
            _serviceHost.Faulted += ServiceHostFaulted;
            _serviceHost.Open();
        }

        private void ServiceHostOpened(object sender, EventArgs e)
        {
            _opened = true;
        }

        private void ServiceHostFaulted(object sender, EventArgs e)
        {
            _serviceHost.Abort();

            if (_opened)
            {
                _opened = false;
                Open();
            }
        }
    }
}